/*
* Copyright 2012 Will Benedict, Felix Berger and Roger Kapsi
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.ardverk.gibson;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.List;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.StringUtils;
/**
* A few utilities to make life easier with {@link Event}s.
*/
public class EventUtils {
// Using MD5 for speed and it's sufficient for this use-case.
private static final String ALGORITHM = "MD5";
private static final byte[] NULL = { 'n', 'u', 'l', 'l' };
private static final int MIN_KEYWORD_LENGTH = 3;
public static Set<String> keywords(String value) {
SortedSet<String> keywords = new TreeSet<String>();
keywords(value, keywords);
return keywords;
}
public static Set<String> keywords(Event event) {
if (event == null) {
throw new NullPointerException("event");
}
SortedSet<String> keywords = new TreeSet<String>();
String message = event.getMessage();
if (message != null) {
keywords(message, keywords);
}
Condition condition = event.getCondition();
if (condition != null) {
keywords(condition, keywords);
}
String marker = event.getMarker();
if (marker != null) {
keywords(marker, keywords);
}
if (keywords.isEmpty()) {
return null;
}
return keywords;
}
private static void keywords(Condition condition, Set<String> dst) {
String message = condition.getMessage();
if (message != null) {
keywords(message, dst);
}
Condition cause = condition.getCause();
if (cause != null) {
keywords(cause, dst);
}
}
private static void keywords(String value, Set<String> dst) {
int length = value.length();
StringBuilder sb = new StringBuilder(length);
for (int i = 0; i < length; i++) {
char ch = value.charAt(i);
if (!Character.isLetterOrDigit(ch)) {
if (sb.length() >= MIN_KEYWORD_LENGTH) {
dst.add(sb.toString());
}
sb.setLength(0);
continue;
}
sb.append(Character.toLowerCase(ch));
}
if (sb.length() >= MIN_KEYWORD_LENGTH) {
dst.add(sb.toString());
}
}
public static String signature(Event event) {
if (event == null) {
throw new NullPointerException("event");
}
MessageDigest md = createMessageDigest(ALGORITHM);
append(md, event.getLogger());
append(md, event.getMarker());
append(md, event.getLevel());
append(md, event.getCondition());
return Base64.encodeBase64URLSafeString(md.digest());
}
private EventUtils() {}
private static void append(MessageDigest md, Condition condition) {
if (condition != null) {
append(md, condition.getTypeName());
append(md, condition.getStackTrace());
append(md, condition.getCause());
}
}
private static void append(MessageDigest md, List<? extends StackTraceElement> elements) {
if (elements != null) {
for (StackTraceElement element : elements) {
append(md, element);
}
}
}
private static void append(MessageDigest md, StackTraceElement element) {
if (element != null) {
append(md, element.getClassName());
append(md, element.getMethodName());
append(md, element.getFileName());
append(md, element.getLineNumber());
}
}
private static void append(MessageDigest md, Enum<?> value) {
append(md, value.getClass());
append(md, value.name());
}
private static void append(MessageDigest md, Class<?> value) {
append(md, value.getName());
}
private static void append(MessageDigest md, String value) {
append(md, StringUtils.getBytesUtf8(value));
}
private static void append(MessageDigest md, int value) {
md.update((byte)(value >>> 24));
md.update((byte)(value >>> 16));
md.update((byte)(value >>> 8));
md.update((byte)(value ));
}
private static void append(MessageDigest md, byte[] value) {
md.update(value != null ? value : NULL);
}
private static MessageDigest createMessageDigest(String algorithm) {
try {
return MessageDigest.getInstance(algorithm);
} catch (NoSuchAlgorithmException err) {
throw new IllegalStateException("NoSuchAlgorithmException: " + algorithm, err);
}
}
}